package com.zhangyang.netty.consumer.proxy;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.codec.LengthFieldPrepender;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
import com.zhangyang.netty.consumer.RpcHandelr;
import com.zhangyang.netty.register.InvokerMsg;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * Created by ASUS on 2017/9/24.
 */
public class RpcProxy{

    public static <T> T create(Class<T> clazz) {

        T object=(T) Proxy.newProxyInstance(clazz.getClassLoader(),new Class[]{clazz},new MethodInvocationHandler(clazz));
        return object;
    }
}

class MethodInvocationHandler implements InvocationHandler {
    private Class clazz;

    public MethodInvocationHandler(Class clazz) {
        this.clazz = clazz;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("MethodInvocationHandler invoke methodName:"+method.getName());
        //判断是如果是本地 调用 传递一个具体的对象  ??????
        if (Object.class.equals(method.getDeclaringClass())) {
            System.out.println("MethodInvocationHandler invoke 11111:");
            return  method.invoke(proxy,args);
        }else{
            System.out.println("MethodInvocationHandler invoke 22222:");
            //如果是接口调用
            return  rpcObject(method,args);
        }
    }

    /**
     * 远程调用
     * @return
     * @param method
     * @param args
     */
    private Object rpcObject(Method method, Object[] args) {

        //初始化 请求参数值
        final InvokerMsg invokerMsg=new InvokerMsg();
        System.out.println("clazz.getName():"+clazz.getName());
        invokerMsg.setClassName(clazz.getName());
        invokerMsg.setMethodName(method.getName());
        invokerMsg.setParams(method.getParameterTypes());
        invokerMsg.setValues(args);


        final RpcHandelr rpcHandler=new RpcHandelr();
        try {
            EventLoopGroup group=new NioEventLoopGroup();
            Bootstrap bootstrap=new Bootstrap();
            bootstrap.group(group).channel(NioSocketChannel.class).option(ChannelOption.TCP_NODELAY,true)
                    .handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();

                        //处理拆包和粘包的解码 编码器！
                        pipeline.addLast("frameDecoder",new LengthFieldBasedFrameDecoder(Integer.MAX_VALUE,0,4,0,4));
                        pipeline.addLast("frameEncoder",new LengthFieldPrepender(4));

                        //加入jdk 序列化 的编码和解码!
                        pipeline.addLast("encoder",new ObjectEncoder());
                        pipeline.addLast("decoder",new ObjectDecoder(Integer.MAX_VALUE, ClassResolvers.cacheDisabled(null)));

                        //加入自己的业务规则
                        pipeline.addLast(rpcHandler);
                    }
            });

           ChannelFuture channelFuture= bootstrap.connect("127.0.0.1",8080).sync();
            channelFuture.channel().writeAndFlush(invokerMsg);
            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }

        return rpcHandler.getResult();
    }
}
